get_page() when access a page of domain.
pages can be removed from domain and freed by another cpu.
To prevent accessing freeing page, use get_page() and put_page()
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
u64 *vpa;
thash_data_t *tlb;
u64 mfn;
+ struct page_info* page;
+ again:
if ( !(VCPU(vcpu, vpsr) & IA64_PSR_IT) ) { // I-side physical mode
gpip = gip;
}
if( gpip){
mfn = gmfn_to_mfn(vcpu->domain, gpip >>PAGE_SHIFT);
if( mfn == INVALID_MFN ) panic_domain(vcpu_regs(vcpu),"fetch_code: invalid memory\n");
- vpa =(u64 *)__va( (gip & (PAGE_SIZE-1)) | (mfn<<PAGE_SHIFT));
}else{
tlb = vhpt_lookup(gip);
if( tlb == NULL)
panic_domain(vcpu_regs(vcpu),"No entry found in ITLB and DTLB\n");
- vpa =(u64 *)__va((tlb->ppn>>(PAGE_SHIFT-ARCH_PAGE_SHIFT)<<PAGE_SHIFT)|(gip&(PAGE_SIZE-1)));
+ mfn = tlb->ppn >> (PAGE_SHIFT - ARCH_PAGE_SHIFT);
}
+
+ page = mfn_to_page(mfn);
+ if (get_page(page, vcpu->domain) == 0) {
+ if (page_get_owner(page) != vcpu->domain) {
+ // This page might be a page granted by another domain.
+ panic_domain(NULL, "domain tries to execute foreign domain "
+ "page which might be mapped by grant table.\n");
+ }
+ goto again;
+ }
+ vpa = (u64 *)__va((mfn << PAGE_SHIFT) | (gip & (PAGE_SIZE - 1)));
+
*code1 = *vpa++;
*code2 = *vpa;
+ put_page(page);
return 1;
}
u64 o_info;
struct domain *d = vcpu->domain;
struct vcpu *v;
+ struct page_info *page;
if(vcpu->domain!=dom0)
return -EPERM;
o_info = (u64)vcpu->domain->shared_info;
+ again:
d->shared_info= (shared_info_t *)domain_mpa_to_imva(vcpu->domain, gpa);
+ page = virt_to_page(d->shared_info);
+ if (get_page(page, d) == 0)
+ goto again;
/* Copy existing shared info into new page */
if (o_info) {
free_xenheap_page((void *)o_info);
} else
memset(d->shared_info, 0, PAGE_SIZE);
+ put_page(page);
return 0;
}
// given a current domain (virtual or metaphysical) address, return the virtual address
static unsigned long
-efi_translate_domain_addr(unsigned long domain_addr, IA64FAULT *fault)
+efi_translate_domain_addr(unsigned long domain_addr, IA64FAULT *fault,
+ struct page_info** page)
{
struct vcpu *v = current;
unsigned long mpaddr = domain_addr;
+ unsigned long virt;
*fault = IA64_NO_FAULT;
+again:
if (v->domain->arch.efi_virt_mode) {
*fault = vcpu_tpa(v, domain_addr, &mpaddr);
if (*fault != IA64_NO_FAULT) return 0;
}
- return ((unsigned long) __va(translate_domain_mpaddr(mpaddr, NULL)));
+ virt = domain_mpa_to_imva(v->domain, mpaddr);
+ *page = virt_to_page(virt);
+ if (get_page(*page, current->domain) == 0) {
+ if (page_get_owner(*page) != current->domain) {
+ // which code is appropriate?
+ *fault = IA64_FAULT;
+ return 0;
+ }
+ goto again;
+ }
+
+ return virt;
}
static efi_status_t
IA64FAULT *fault)
{
unsigned long tv = 0, tc = 0;
+ struct page_info *tv_page = NULL;
+ struct page_info *tc_page = NULL;
efi_status_t status;
//printf("efi_get_time(%016lx,%016lx) called\n", tv_addr, tc_addr);
- tv = efi_translate_domain_addr(tv_addr, fault);
- if (*fault != IA64_NO_FAULT) return 0;
+ tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);
+ if (*fault != IA64_NO_FAULT)
+ return 0;
if (tc_addr) {
- tc = efi_translate_domain_addr(tc_addr, fault);
- if (*fault != IA64_NO_FAULT) return 0;
+ tc = efi_translate_domain_addr(tc_addr, fault, &tc_page);
+ if (*fault != IA64_NO_FAULT) {
+ put_page(tv_page);
+ return 0;
+ }
}
//printf("efi_get_time(%016lx,%016lx) translated to xen virtual address\n", tv, tc);
status = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
//printf("efi_get_time returns %lx\n", status);
+ if (tc_page != NULL)
+ put_page(tc_page);
+ put_page(tv_page);
return status;
}
vcpu_get_domain_bundle(VCPU* vcpu, REGS* regs, UINT64 gip, IA64_BUNDLE* bundle)
{
UINT64 gpip;// guest pseudo phyiscal ip
+ unsigned long vaddr;
+ struct page_info* page;
+again:
#if 0
// Currently xen doesn't track psr.it bits.
// it assumes always psr.it = 1.
gpip = ((tr.pte.ppn >> (tr.ps - 12)) << tr.ps) |
(gip & ((1 << tr.ps) - 1));
}
-
- *bundle = *((IA64_BUNDLE*)__va(__gpa_to_mpa(vcpu->domain, gpip)));
+
+ vaddr = domain_mpa_to_imva(vcpu->domain, gpip);
+ page = virt_to_page(vaddr);
+ if (get_page(page, vcpu->domain) == 0) {
+ if (page_get_owner(page) != vcpu->domain) {
+ // This page might be a page granted by another
+ // domain.
+ panic_domain(regs,
+ "domain tries to execute foreign domain "
+ "page which might be mapped by grant "
+ "table.\n");
+ }
+ goto again;
+ }
+ *bundle = *((IA64_BUNDLE*)vaddr);
+ put_page(page);
return 1;
}